﻿using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Collections;

namespace Job.Core.Collections
{
    /// <summary>
    /// 对 Enumerable 的相关扩展。
    /// </summary>
    public static class EnumerableExtensions
    {
        /// <summary>
        /// 遍历列表中的每一个项，并返回每项通过func处理返回值相 + 的结果。
        /// </summary>
        /// <typeparam name="TSource">源类型。</typeparam>
        /// <typeparam name="TResult">结果类型。</typeparam>
        /// <param name="source">需遍历的序列。</param>
        /// <param name="func">用于生成处理结果的委托。</param>
        /// <returns>每项通过委托处理后相 + 的结果。</returns>
        public static TResult ForEach<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> func)
        {
            TResult result = default(TResult);

            if (source == null)
                return result;

            bool first = true;

            foreach (var item in source)
            {
                if (first)
                {
                    result = func.Invoke(item);
                    first = false;
                }
                else
                {
                    result = AddOperation<TResult>.Add(result, func.Invoke(item));
                }
            }

            return result;
        }

        /// <summary>
        /// 遍历列表中的每一个项，并返回每项通过func处理返回值相 + 的结果。
        /// </summary>
        /// <typeparam name="TResult">源类型。</typeparam>
        /// <param name="source">结果类型。</param>
        /// <param name="func">用于生成处理结果的委托。</param>
        /// <returns>每项通过委托处理后相 + 的结果。</returns>
        public static TResult ForEach<TResult>(this IEnumerable source, Func<object, TResult> func)
        {
            TResult result = default(TResult);

            if (source == null)
                return result;

            bool first = true;

            foreach (var item in source)
            {
                if (first)
                {
                    result = func.Invoke(item);
                    first = false;
                }
                else
                {
                    result = AddOperation<TResult>.Add(result, func.Invoke(item));
                }
            }

            return result;
        }

        #region AddOperation

        /// <summary>
        /// 处理通用类型的相加操作。
        /// </summary>
        /// <typeparam name="T"></typeparam>
        static class AddOperation<T>
        {
            static AddOperation()
            {
                if (typeof(T) == typeof(string))
                {
                    var strAdd = new Func<string, string, string>((x, y) => x + y);
                    add = (Func<T, T, T>)(object)strAdd;
                }
                else
                {
                    var x = Expression.Parameter(typeof(T), "x");
                    var y = Expression.Parameter(typeof(T), "y");
                    var body = Expression.Add(x, y);
                    var lambda = Expression.Lambda<Func<T, T, T>>(body, x, y);
                    add = lambda.Compile();
                }
            }

            private static Func<T, T, T> add;

            public static T Add(T x, T y)
            {
                return add(x, y);
            }
        }

        #endregion

    }    
}